package org.opensuse.bs.ui.views;

import java.io.File;
import java.util.Set;
import java.util.Vector;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ITreeSelection;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.forms.events.ExpansionAdapter;
import org.eclipse.ui.forms.events.ExpansionEvent;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.ScrolledForm;
import org.eclipse.ui.forms.widgets.Section;
import org.eclipse.ui.forms.widgets.TableWrapData;
import org.eclipse.ui.forms.widgets.TableWrapLayout;
import org.eclipse.ui.part.ViewPart;
import org.opensuse.bs.ui.BSUIPlugin;
import org.opensuse.bs.ui.IBSUIConstants;
import org.opensuse.bs.ui.OSC;
import org.opensuse.bs.ui.model.BSModelElement;
import org.opensuse.bs.ui.model.RemotePackage;
import org.opensuse.bs.ui.model.RemoteProject;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

public class Properties extends ViewPart implements ISelectionListener {
	//UI elements of this view
	private FormToolkit toolkit;
	private ScrolledForm form;
	private Text title;
	private Text des;
	private Table persons;
	private Table repos;
	private Button[] buttons; //2 "Add" buttons and 2 "Remove" buttons
	private Section section2;
	
	//fields for implementing actions of this view
	private ITreeSelection selected; //store the last selected element
	private Document doc;//sotre the currently meta dom
	private boolean editable; //indicate if the view is editable for the plugin user or not
	
	//actions for properties view
	private Action uploadAction;
	private Action refreshAction;
	
	private class PersonDialog extends Dialog {
		private Text userID;
		private boolean isMaintainer; //false to be a bugowner;
		
		public PersonDialog(Shell parentShell) {
			super(parentShell);
		}
		
		protected Control createDialogArea(Composite parent) {
			Composite client = new Composite(parent, SWT.NONE);
			GridLayout layout = new GridLayout();
			client.setLayout(layout);
			layout.numColumns = 2;
			
			Label label = new Label(client, SWT.NONE);
			label.setText("User ID:");
			GridData gd = new GridData();
			userID = new Text(client, SWT.BORDER);
			userID.setLayoutData(gd);
			gd.grabExcessHorizontalSpace = true;
			gd.horizontalAlignment = SWT.FILL;
			gd.widthHint = 200;
			
			Button button1 = new Button(client, SWT.RADIO);
			button1.setText("Maintainer");
			gd = new GridData();
			button1.setLayoutData(gd);
			gd.grabExcessHorizontalSpace = true;
			gd.widthHint = 100;
			button1.addSelectionListener(new SelectionAdapter() {
				public void widgetSelected(SelectionEvent e) {
					isMaintainer = true;
				}
			});
			
			Button button2 = new Button(client, SWT.RADIO);
			button2.setText("Bugowner");
			gd = new GridData();
			button2.setLayoutData(gd);
			gd.grabExcessHorizontalSpace = true;
			gd.widthHint = 100;
			button2.addSelectionListener(new SelectionAdapter() {
				public void widgetSelected(SelectionEvent e) {
					isMaintainer = false;
				}
			});
			
			return client;
		}
		
		protected void okPressed() {
			String[] result = new String[2];
			result[0] = userID.getText().trim();
			if(isMaintainer) {
				result[1] = "maintainer";
			}
			else {
				result[1] = "bugowner";
			}
			TableItem item = new TableItem(persons, SWT.NONE);
			item.setText(result);
			close();
		}
	}
	
	private class RepoDialog extends Dialog {
		private String distro;
		private Button[] buttons;
		
		public RepoDialog(Shell parentShell) {
			super(parentShell);
			distro = "";
		}
		
		protected Control createDialogArea(Composite parent) {
			Composite client = new Composite(parent, SWT.NONE);
			GridLayout layout = new GridLayout();
			client.setLayout(layout);
			layout.numColumns = 2;
			
			Label label = new Label(client, SWT.NONE);
			label.setText("Repository:");
			final Combo repos = new Combo(client, SWT.DROP_DOWN);
			Set<String> distros = BSUIPlugin.getDefault().getDistros().keySet();
			for(String distro : distros) {
				repos.add(distro);
			}
			repos.addSelectionListener(new SelectionAdapter() {
				public void widgetSelected(SelectionEvent e) {
					int index = repos.getSelectionIndex();
					if(index != -1) {
						distro = repos.getItem(index);
					}
				}
			});
			
			buttons = new Button[2];
			buttons[0] = new Button(client, SWT.CHECK);
			buttons[0].setText("i586");
			buttons[0].setSelection(true);
			GridData gd = new GridData();
			buttons[0].setLayoutData(gd);
			gd.grabExcessHorizontalSpace = true;
			gd.widthHint = 80;
			
			buttons[1] = new Button(client, SWT.CHECK);
			buttons[1].setText("x86_64");
			buttons[1].setSelection(true);
			gd = new GridData();
			buttons[1].setLayoutData(gd);
			gd.grabExcessHorizontalSpace = true;
			gd.widthHint = 80;
			
			return client;
		}
		
		protected void okPressed() {
			TableItem item = new TableItem(repos, SWT.NONE);
			String[] r = new String[2];
			r[0] = distro;
			r[1] = "";
			if(buttons[0].getSelection())
				r[1] += "i586 ";
			if(buttons[1].getSelection())
				r[1] += "x86_64 ";
			r[1] = r[1].trim();
			item.setText(r);
			close();
		}
	}
	
	/*
	 *  This method is used to show meta info 
	 * of the currently selected project/package
	 * in properties view.
	 */
	private void updateView(ITreeSelection current) {
		TreePath[] paths = current.getPaths();
		for(TreePath path : paths) {
			final BSModelElement element = (BSModelElement) path.getLastSegment();
			final String name = element.getName();
			title.setText("");
			des.setText("");
			persons.removeAll();
			repos.removeAll();
			for(Button button : buttons) {
				button.setEnabled(false);
			}
			title.setEditable(false);
			des.setEditable(false);
			section2.setVisible(true);
			final String user = BSUIPlugin.getDefault().getUser();
			if(element instanceof RemoteProject) {
				form.setText("Info of Project "+name);
				Job job = new Job("Getting information of project "+name) {
					public IStatus run(IProgressMonitor monitor) {
						try {
							doc = OSC.toXML("req -m GET /source/"+name+"/_meta");
							if(doc == null) {
								return Status.CANCEL_STATUS;
							}
							final NodeList titlelist = doc.getElementsByTagName("title");
							final NodeList deslist = doc.getElementsByTagName("description");
							final NodeList personlist = doc.getElementsByTagName("person");
							final NodeList repolist = doc.getElementsByTagName("repository");
							if(monitor.isCanceled())
								return Status.CANCEL_STATUS;
							Display display = BSUIPlugin.getDefault().getWorkbench().getDisplay();
							display.asyncExec(new Runnable() {
								public void run() {
									title.setText(titlelist.item(0).getTextContent());
									des.setText(deslist.item(0).getTextContent());
									editable = false; //view is uneditable
									final int person_num = personlist.getLength();
									for(int i=0;i<person_num;i++) {
										Element person = (Element) personlist.item(i);
										String[] tmp = new String[2];
										tmp[0] = person.getAttribute("userid"); //userid
										tmp[1] = person.getAttribute("role"); //role
										if(tmp[1].equals("maintainer") && tmp[0].equals(user)) {
											editable = true; //if the user invovles the project
										}
										TableItem item = new TableItem(persons, SWT.NONE);
										item.setText(tmp);
									}
									if(editable) { //make the view editable
										for(Button button : buttons) {
											button.setEnabled(true);
										}
										title.setEditable(true);
										des.setEditable(true);
									}
									final int repo_num = repolist.getLength();
									for(int i=0;i<repo_num;i++) {
										Element repo = (Element) repolist.item(i);
										String[] tmp = new String[2];
										tmp[0] = repo.getAttribute("name"); //repo name
										tmp[1] = "";
										NodeList archlist = repo.getChildNodes();
										for(int j=0; j<archlist.getLength();j++) {
											tmp[1] += (archlist.item(j).getTextContent()+" ");
										}
										tmp[1] = tmp[1].trim();
										TableItem item = new TableItem(repos, SWT.NONE);
										item.setText(tmp);
									}
								}
							});
						}catch(Exception e) {
							e.printStackTrace();
						}
						return Status.OK_STATUS;
					}
				};
				job.schedule();
			}else if(element instanceof RemotePackage) {
				form.setText("Info of Package "+name);
				section2.setVisible(false);
				Job job = new Job("Getting information of project "+name) {
					public IStatus run(IProgressMonitor monitor) {
						try {
							BSModelElement p = (BSModelElement) element.getParent(element);
							String parent = p.getName();
							
							/*parse meta of the pkg*/
							doc = OSC.toXML("req -m GET /source/"+parent+"/"+name+"/_meta");
							if(doc == null) {
								return Status.CANCEL_STATUS;
							}
							final NodeList pkgtitle = doc.getElementsByTagName("title");
							final NodeList pkgdes = doc.getElementsByTagName("description");
							final NodeList personlist = doc.getElementsByTagName("person");
							
							/*parse meta of the parent prj*/
							Document doc_tmp = OSC.toXML("req -m GET /source/"+parent+"/_meta");
							if(doc_tmp == null) {
								return Status.CANCEL_STATUS;
							}
							final NodeList prjpersonlist = doc_tmp.getElementsByTagName("person");
							if(monitor.isCanceled())
								return Status.CANCEL_STATUS;
							
							Display display = BSUIPlugin.getDefault().getWorkbench().getDisplay();
							display.asyncExec(new Runnable() {
								public void run() {
									title.setText(pkgtitle.item(0).getTextContent());
									des.setText(pkgdes.item(0).getTextContent());
									editable = false; //view is uneditable
									for(int i=0;i<personlist.getLength();i++) {
										Element person = (Element) personlist.item(i);
										String[] tmp = new String[2];
										tmp[0] = person.getAttribute("userid"); //userid
										tmp[1] = person.getAttribute("role"); //role
										if(tmp[1].equals("maintainer") && tmp[0].equals(user)) {
											editable = true; //if the user invovles the project
										}
										TableItem item = new TableItem(persons, SWT.NONE);
										item.setText(tmp);
									}
									for(int i=0;i<prjpersonlist.getLength();i++) {
										Element person = (Element) prjpersonlist.item(i);
										String[] tmp = new String[2];
										tmp[0] = person.getAttribute("userid"); //userid
										tmp[1] = person.getAttribute("role"); //role
										if(tmp[1].equals("maintainer") && tmp[0].equals(user)) {
											editable = true; //if the user invovles the project
										}
									}
									if(editable) { //make the view editable
										buttons[0].setEnabled(true);
										buttons[1].setEnabled(true);
										title.setEditable(true);
										des.setEditable(true);
									}
								}
							});
						}catch(Exception e) {
							e.printStackTrace();
						}
						return Status.OK_STATUS;
					}
				};
				job.schedule();
			}
		}
	}
	
	/*
	 * This method uses meta info in properties view
	 *  to update meta of the currently project/package
	 */
	private void uploadMeta() {
		if(!editable || !diff())return;
		TreePath path = selected.getPaths()[0];
		BSModelElement element = (BSModelElement) path.getLastSegment();
		final String name = element.getName();
		final String projectname = ((BSModelElement) path.getFirstSegment()).getName();
		try {
			String up_title = title.getText().trim();
			doc.getElementsByTagName("title").item(0).setTextContent(up_title);
			
			String up_des = des.getText().trim();
			doc.getElementsByTagName("description").item(0).setTextContent(up_des);
			
			NodeList personlist = doc.getElementsByTagName("person");
			TableItem[] person_t = persons.getItems();
			//delete removed person obj in doc
			int size = personlist.getLength();
			for(int i=size-1;i>-1;i--) {
				Element person = (Element) personlist.item(i);
				String userid = person.getAttribute("userid");
				String role = person.getAttribute("role");
				boolean has = false;
				for(int j=0;j<person_t.length;j++) {
					TableItem item = person_t[j];
					if(item.getText(0).equals(userid) && item.getText(1).equals(role)) {
						has = true;
						break;
					}
				}
				if(!has) {
					doc.getDocumentElement().removeChild(person);
				}
			}
			personlist = doc.getElementsByTagName("person"); //refresh psersonlist
			NodeList repolist = doc.getElementsByTagName("repository");
			size = personlist.getLength();
			for(int i=0;i<person_t.length;i++) {
				String t_userid = person_t[i].getText(0);
				String t_role = person_t[i].getText(1);
				boolean has = false;
				for(int j=size-1;j>-1;j--) {
					Element person = (Element) personlist.item(j);
					if(person.getAttribute("userid").equals(t_userid)
							&&
							person.getAttribute("role").equals(t_role)) {
						has = true;
						break;
					}
				}
				if(!has) {
					Element newPerson = doc.createElement("person");
					Attr attr1 = doc.createAttribute("role");
					attr1.setValue(t_role);
					Attr attr2 = doc.createAttribute("userid");
					attr2.setValue(t_userid);
					newPerson.setAttributeNode(attr1);
					newPerson.setAttributeNode(attr2);
					if(repolist == null) {
						doc.getDocumentElement().appendChild(newPerson);
					}
					else {
						doc.getDocumentElement().insertBefore(newPerson, repolist.item(0));
					}
				}
			}
			
			if(element instanceof RemoteProject) {
				if(repolist != null) {
					TableItem[] repo_t = repos.getItems();
					int rlength = repolist.getLength();
					for(int i=rlength-1;i>-1;i--) {
						Element repo = (Element) repolist.item(i);
						String reponame = repo.getAttribute("name");
						NodeList archs = repo.getElementsByTagName("arch");
						boolean has = false;
						for(int j=0;j<repo_t.length;j++) {
							TableItem item = repo_t[j];
							if(item.getText(0).equals(reponame)) {
								String archs_t = item.getText(1);
								int same = 0;
								for(int k=0;k<archs.getLength();k++) {
									if(archs_t.indexOf(archs.item(k).getTextContent()) != -1)
										same += 1;
								}
								if(same == archs.getLength()) {
									has = true;
									break;
								}
							}
						}
						if(!has) {
							doc.getDocumentElement().removeChild(repo);
						}
					}
					repolist = doc.getElementsByTagName("repository");
					rlength = repolist.getLength();
					for(int i=0;i<repo_t.length;i++) {
						String reponame = repo_t[i].getText(0);
						String arch_t = repo_t[i].getText(1);
						boolean has = false;
						for(int j=rlength-1;j>-1;j--) {
							Element repo = (Element) repolist.item(j);
							if(repo.getAttribute("name").equals(reponame)) {
								NodeList archs = repo.getElementsByTagName("arch");
								int same = 0;
								for(int k=0;k<archs.getLength();k++) {
									if(arch_t.indexOf(archs.item(k).getTextContent()) != -1) {
										same += 1;
									}
								}
								if(same == archs.getLength()) {
									has = true;
									break;
								}
							}
						}
						if(!has) {
							Element newRepo = doc.createElement("repository");
							Attr attr1 = doc.createAttribute("name");
							attr1.setValue(reponame);
							newRepo.setAttributeNode(attr1);
							String[] newArchs = arch_t.split(" ");
							for(int j=0;j<newArchs.length;j++) {
								Element newArch = doc.createElement("arch");
								newArch.setTextContent(newArchs[j]);
								newRepo.appendChild(newArch);
							}
							doc.getDocumentElement().appendChild(newRepo);
						}
					}
				}
				
				final File file = OSC.toFile(doc, "upload_meta");				
				Job job = new Job("Uploading meta of project "+name) {
					public IStatus run(IProgressMonitor monitor) {
						Vector<String> result = OSC.run("meta prj "+name+" -F "+file.getAbsolutePath());
						file.delete();
						if(result.isEmpty()) {
							return Status.CANCEL_STATUS;
						}
						return Status.OK_STATUS;
					}
				};
				job.schedule();
			}
			else if(element instanceof RemotePackage) {
				final File file = OSC.toFile(doc, "upload_meta");
				Job job = new Job("Uploading meta of package "+name) {
					public IStatus run(IProgressMonitor monitor) {
						Vector<String> result = OSC.run("meta pkg "+projectname+" "+name+" -F "+file.getAbsolutePath());
						file.delete();
						if(result.isEmpty()) {
							return Status.CANCEL_STATUS;
						}
						return Status.OK_STATUS;
					}
				};
				job.schedule();
			}
		}catch(Exception e) {
			e.printStackTrace();
		}
	}

	/*
	 * This method decides whether the meta info
	 * shown in properties view has been changed
	 */
	private boolean diff() {
		NodeList titleNodes = doc.getElementsByTagName("title");
		if(!title.getText().equals(titleNodes.item(0).getTextContent())) {
			return true;
		}
		
		NodeList desNodes = doc.getElementsByTagName("description");
		if(!des.getText().equals(desNodes.item(0).getTextContent())) {
			return true;
		}
		
		NodeList personNodes = doc.getElementsByTagName("person");
		if(personNodes.getLength() != persons.getItemCount()) {
			return true;
		}
		int size = personNodes.getLength();
		for(int i=0;i<size;i++) {
			Element person = (Element) personNodes.item(i);
			String userid = person.getAttribute("userid");
			String role = person.getAttribute("role");
			boolean has = false;
			for(int j=0;j<size;j++) {
				TableItem item = persons.getItem(j);
				if(item.getText(0).equals(userid)) {
					if(item.getText(1).equals(role)) {
						has = true;
						break;
					}
				}
			}
			if(!has) {
				return true;
			}
		}

		NodeList repoNodes = doc.getElementsByTagName("repository");
		if(repoNodes != null) {
			if(repoNodes.getLength() != repos.getItemCount()) {
				return true;
			}
			size = repoNodes.getLength();
			for(int i=0;i<size;i++) {
				Element repo = (Element) repoNodes.item(i);
				String reponame = repo.getAttribute("name");
				NodeList archlist = repo.getElementsByTagName("arch");
				boolean has = false;
				for(int j=0;j<size;j++) {
					TableItem item = repos.getItem(j);
					if(item.getText(0).equals(reponame)) {
						String archs = item.getText(1);
						for(int k=0;k<archlist.getLength();k++) {
							if(archs.indexOf(archlist.item(k).getTextContent()) == -1)
								return true;
						}
						has = true;
					}
				}
				if(!has) {
					return true;
				}
			}
		}
		
		return false;
	}
	
	public Properties() {
		selected = null;
	}
	
	public void createPartControl(Composite parent) {
		buttons = new Button[4];
		
		toolkit = new FormToolkit(parent.getDisplay());
		form = toolkit.createScrolledForm(parent);
		form.setText("Info Page");
		
		TableWrapLayout layout = new TableWrapLayout();
		form.getBody().setLayout(layout);
		layout.numColumns = 4;
		
		Section section0 = toolkit.createSection(form.getBody(), 
				Section.TITLE_BAR|Section.EXPANDED|Section.TWISTIE);
		section0.addExpansionListener(new ExpansionAdapter() {
			public void expansionStateChanged(ExpansionEvent e) {
				form.reflow(true);
			}
		});
		TableWrapData td = new TableWrapData(TableWrapData.FILL_GRAB);
		section0.setLayoutData(td);
		td.colspan = 4;
		section0.setText("General Info");
		toolkit.createCompositeSeparator(section0);
		Composite client0 = toolkit.createComposite(section0);
		
		GridLayout glayout = new GridLayout();
		glayout.numColumns = 4;
		client0.setLayout(glayout);
		section0.setClient(client0);
		
		toolkit.createLabel(client0, "Title:");
		title = toolkit.createText(client0, "",SWT.BORDER|SWT.WRAP);
		title.setEditable(false);
		GridData gd = new GridData();
		title.setLayoutData(gd);
		gd.grabExcessHorizontalSpace = true;
		gd.horizontalAlignment = SWT.FILL;
		gd.horizontalSpan = 4;
		
		toolkit.createLabel(client0, "Description:");
		des = toolkit.createText(client0, "", SWT.BORDER|SWT.H_SCROLL|SWT.V_SCROLL|SWT.WRAP);
		des.setEditable(false);
		gd = new GridData();
		des.setLayoutData(gd);
		gd.grabExcessHorizontalSpace = true;
		gd.horizontalAlignment = SWT.FILL;
		gd.heightHint = 100;
		gd.horizontalSpan = 4;
		
		//persons section
		Section section1 = toolkit.createSection(form.getBody(), 
				Section.TITLE_BAR|Section.DESCRIPTION);
		td = new TableWrapData(TableWrapData.FILL_GRAB);
		section1.setLayoutData(td);
		td.colspan = 2;
		section1.setText("Involved Users");
		section1.setDescription("Users who maintain or deal with bugs of the project/package.");
		Composite client1 = toolkit.createComposite(section1);
		glayout = new GridLayout();
		glayout.numColumns = 2;
		client1.setLayout(glayout);
		section1.setClient(client1);
		
		persons = toolkit.createTable(client1, SWT.BORDER);
		TableColumn tc1 = new TableColumn(persons, SWT.CENTER);
		TableColumn tc2 = new TableColumn(persons, SWT.CENTER);
		tc1.setText("User ID");
		tc2.setText("Role");
		tc1.setWidth(100);
		tc2.setWidth(100);
		persons.setHeaderVisible(true);
		persons.setLinesVisible(true);
		gd = new GridData();
		persons.setLayoutData(gd);
		gd.grabExcessHorizontalSpace = true;
		gd.horizontalAlignment = SWT.FILL;
		gd.verticalSpan = 2;
		gd.grabExcessVerticalSpace = true;
		gd.verticalAlignment = SWT.FILL;
		gd.heightHint = 150;
		
		buttons[0] = new Button(client1, SWT.PUSH);
		buttons[0].setText("Add");
		gd = new GridData();
		buttons[0].setLayoutData(gd);
		gd.widthHint = 80;
		buttons[0].addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				PersonDialog dialog = new PersonDialog(form.getShell());
				dialog.open();
			}
		});
		buttons[0].setEnabled(false);
		
		buttons[1] = new Button(client1, SWT.PUSH);
		buttons[1].setText("Remove");
		gd = new GridData();
		buttons[1].setLayoutData(gd);
		gd.widthHint = 80;
		gd.verticalAlignment = SWT.BEGINNING;
		buttons[1].addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				if(persons.getSelectionCount() != 0) {
					int[] items = persons.getSelectionIndices();
					for(int i=0;i<items.length;i++) {
						persons.remove(items[i]);
					}
				}
			}
		});
		buttons[1].setEnabled(false);
		
		//repositories' section
		section2 = toolkit.createSection(form.getBody(), 
				Section.TITLE_BAR|Section.DESCRIPTION);
		td = new TableWrapData(TableWrapData.FILL_GRAB);
		section2.setLayoutData(td);
		td.colspan = 2;
		section2.setText("Build Repositories");
		section2.setDescription("Add repositories to enable the build monitor");
		Composite client2 = toolkit.createComposite(section2);
		glayout = new GridLayout();
		glayout.numColumns = 2;
		client2.setLayout(glayout);
		section2.setClient(client2);
		
		repos = toolkit.createTable(client2, SWT.BORDER);
		TableColumn tc3 = new TableColumn(repos, SWT.CENTER);
		TableColumn tc4 = new TableColumn(repos, SWT.CENTER);
		tc3.setText("Name");
		tc4.setText("Achitecture");
		tc3.setWidth(100);
		tc4.setWidth(100);
		repos.setHeaderVisible(true);
		repos.setLinesVisible(true);
		
		gd = new GridData();
		repos.setLayoutData(gd);
		gd.grabExcessHorizontalSpace = true;
		gd.horizontalAlignment = SWT.FILL;
		gd.verticalSpan = 2;
		gd.grabExcessVerticalSpace = true;
		gd.verticalAlignment = SWT.FILL;
		gd.heightHint = 150;
		
		buttons[2] = new Button(client2, SWT.PUSH);
		buttons[2].setText("Add");
		gd = new GridData();
		buttons[2].setLayoutData(gd);
		gd.widthHint = 80;
		buttons[2].addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				RepoDialog dialog = new RepoDialog(form.getShell());
				dialog.open();
			}
		});
		buttons[2].setEnabled(false);
		
		buttons[3] = new Button(client2, SWT.PUSH);
		buttons[3].setText("Remove");
		gd = new GridData();
		buttons[3].setLayoutData(gd);
		gd.widthHint = 80;
		gd.verticalAlignment = SWT.BEGINNING;
		buttons[3].addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				if(repos.getSelectionCount() != 0) {
					int[] items = repos.getSelectionIndices();
					for(int i=0;i<items.length;i++) {
						repos.remove(items[i]);
					}
				}
			}
		});
		buttons[3].setEnabled(false);
		
		getViewSite().getPage().addSelectionListener(this);
		
		BSUIPlugin plugin = BSUIPlugin.getDefault();
		uploadAction = new Action("Upload") {
			public void run() {
				uploadMeta();
			}
		};
		uploadAction.setHoverImageDescriptor(
				plugin.getImageDescriptor(IBSUIConstants.IMG_UPLOAD));
		uploadAction.setToolTipText("Upload modified meta shown in the properties view.");
		
		refreshAction = new Action("Refresh") {
			public void run() {
				if(selected != null) {
					updateView(selected);
				}
			}
		};
		refreshAction.setHoverImageDescriptor(
				plugin.getImageDescriptor(IBSUIConstants.IMG_REFRESH));
		refreshAction.setToolTipText("Refresh properties view " +
				"according to the current selected item in remote view.");
		
		IActionBars bars = getViewSite().getActionBars();
		IToolBarManager tbm = bars.getToolBarManager();
		tbm.add(uploadAction);
		tbm.add(refreshAction);
		bars.updateActionBars();
	}

	public void setFocus() {
		form.setFocus();
	}
	
	public void selectionChanged(IWorkbenchPart part, ISelection selection) {
		if(part instanceof RemoteView && selection instanceof ITreeSelection) {
			ITreeSelection current = (ITreeSelection) selection;
			if(selected != null && selected.equals(current)) {
				return; // selected tree item isn't changed
			}
			if(selected != null && editable) {
				if(diff()) { // meta of the former selected item has been changed 
					          // but hasn't been uploaded yet
					if(MessageDialog.openQuestion(
							form.getShell(), 
							"Not Upload yet", 
							"You haven't uploaded the new meta yet. Upload it now?")) {
						uploadMeta();
					}
				}
			}
			
			selected = current;
			updateView(current);
		}
	}

}
